
-module(server_reader).

-export([
		 start_link/0, 
		 init/0
		]).

-record(client, {pid_send}).

-define(HEART_TIMEOUT, 60000). 
-define(HEADER_LENGTH, 4).    % 消息头长度，async_recv需等到这么多才会开始接受数据

%%--------------------------------------------------------------------------

start_link() ->
    {ok, proc_lib:spawn_link(?MODULE, init, [])}.

init() ->
	Client = #client{pid_send = undefined},
	receive
		{go, Socket} ->
			try
				Pid_send = spawn_link(fun() -> send_msg(Socket) end),
				get_socket_data(Socket, Client#client{pid_send = Pid_send})
			catch
				_:Reason ->
					client_lost(Socket, Client, {error, Reason}),
					error
			end;
		_Other ->
			skip
	end.

%%--------------------------------------------------------------------------

get_socket_data(Socket, Client) ->
	Ref = async_recv(Socket, ?HEADER_LENGTH, ?HEART_TIMEOUT),
	receive
		{inet_async, Socket, Ref, {ok, <<Len:16, MsgId:16>>}} ->
			get_msg_data(Socket, Client, MsgId, Len);
		{inet_async, Socket, Ref, {error,timeout}} ->
			client_lost(Socket, Client, {error,timeout});
		{inet_async, Socket, Ref, {error,closed}} ->
			io:format("socket ~p closed ~n", [Socket]),
			erlang:port_close(Socket);
		Other -> 
            client_lost(Socket, Client, Other)
	end.

get_msg_data(Socket, Client, MsgId, Len) ->
	case MsgId of
		10000 ->
			io:format("Msg heartbeat 10000 ~n"),
			Client#client.pid_send ! {send, <<"server receive heartbeat">>},
			get_socket_data(Socket, Client);
		_Other ->
			MsgLen = Len - ?HEADER_LENGTH,
			case MsgLen > 0 of
				true ->
					Ref = async_recv(Socket, MsgLen, ?HEART_TIMEOUT),
					receive
						{inet_async, Socket, Ref, {ok, Binary}} ->
							io:format("msg id: ~p~ndata:~p~n", [MsgId, Binary]),
							get_socket_data(Socket, Client);
						{inet_async, Socket, Ref, {error,timeout}} ->
							client_lost(Socket, Client, {error,timeout});  
						Other -> 
							client_lost(Socket, Client, Other)
					end;
				false ->
					client_lost(Socket, Client, empty_msg)
			end
	end.

%% 发送进程
send_msg(Socket) ->
	receive
		{send, Data} ->
			catch erlang:port_command(Socket, Data, [force]),
			%%gen_tcp:send(Socket, Data),
			send_msg(Socket);
		{inet_reply, _Sock, ok} ->
			send_msg(Socket);
		{inet_reply, _Sock, Result} ->
			io:format("send msg error ~p~n", [Result]);
		Other ->
			io:format("send msg ~p~n", [Other]),
			send_msg(Socket)
	end.

%% 断开连接
client_lost(Socket, _Client, Reason) ->
	timer:sleep(100),
	catch erlang:port_close(Socket),
    exit({unexpected_message, Reason}).

%% 接收数据
async_recv(Sock, Length, Timeout) when is_port(Sock) ->
    case prim_inet:async_recv(Sock, Length, Timeout) of
        {error, Reason} -> 	
			throw({Reason});
        {ok, Res}       ->  
			Res;
        Res             ->	
			Res
    end.